package com.fxm.service.jobhandler;

import com.fxm.domain.Rank;
import com.fxm.domain.Record;
import com.fxm.service.RankService;
import com.fxm.service.RecordService;
import com.fxm.utils.TimeUtilCustomize;
import com.fxm.vo.IsRightVO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Queues;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;


/**
 * <p>
 * 最大连胜和最大连败
 * </p>
 *
 * @author fxm
 * @since 2021-01-30
 */
@Component
@Slf4j
public class MaxCorrectAndErrorJob {

    @Autowired
    private RecordService recordService;

    @Autowired
    private RankService rankService;

    private String status;

    private Map<String, List<Integer>> saveMap = Maps.newHashMap();

    /**
     * 计算用户答题最大连胜和最大连败任务 每天凌晨1点整执行一次
     * @throws Exception
     */
    @XxlJob("maxCorrectAndErrorJob")
    public ReturnT<String> maxCorrectAndErrorJob(String param) throws Exception {
        log.info("计算用户答题最大连胜和最大连败任务开始>>>>>>>>>>");

        //读取数据源（answer_record表）
        List<Record> recordList = recordService.list();

        //无数据 任务执行失败
        if (Objects.isNull(recordList) || recordList.size() == 0) {
            return ReturnT.FAIL;
        }

        //集合转队列
        Queue<Record> queue = new ArrayBlockingQueue<>(recordList.size());
        for (Record record : recordList) {
            queue.add(record);
        }

        //数据递归转化
        Map<String, List<Record>> recordMap = Maps.newHashMap();
        dataMapping(queue, recordMap);

        //计算最大连胜和连败次数
        Map<String, IsRightVO> countMap = calculationMaxCorrectAndError(recordMap);

        //sink到answer_rank表
        for (Map.Entry<String, IsRightVO> entry : countMap.entrySet()) {
            String openid = entry.getKey();
            IsRightVO isRightVO = entry.getValue();

            //根据openid和date日期 查询rank表主键id
            Rank rankByOpenidAndDate = rankService.getRankByOpenidAndDate(openid,
                    TimeUtilCustomize.parseDateToStr(TimeUtilCustomize.DATE_DAY_FORMAT, new Date()));

            //查询数据不为null
            if (Objects.nonNull(rankByOpenidAndDate)) {

                Rank rank = Rank.builder()
                        .id(rankByOpenidAndDate.getId())
                        .openid(openid)
                        .maxCorrect(isRightVO.getMaxCorrect())
                        .maxError(isRightVO.getMaxError())
                        .build();

                //更新当天排行表该用户信息
                rankService.updateRank(rank);
            }

        }

        log.info("计算用户答题最大连胜和最大连败任务结束<<<<<<<<<<");
        return ReturnT.SUCCESS;
    }

    /**
     * 计算最大连胜和连败次数
     * @param recordMap
     * @return
     */
    private Map<String, IsRightVO> calculationMaxCorrectAndError(Map<String, List<Record>> recordMap) {
        Map<String, IsRightVO> countMap = Maps.newHashMap();

        for (Map.Entry<String, List<Record>> entry : recordMap.entrySet()) {

            //集合转队列
            List<Record> recordList = entry.getValue();
            Queue<Record> queue = Queues.newArrayBlockingQueue(recordList.size());

            for (Record record : recordList) {
                queue.add(record);
            }

            //递归计算
            Map<String, Integer> resultMap = Maps.newHashMap();
            calculation(queue, resultMap);

            //计算结果组装为想要的数据格式
            IsRightVO isRightVO = new IsRightVO();

            for (Map.Entry<String, List<Integer>> saveEntry : saveMap.entrySet()) {
                List<Integer> countList = saveEntry.getValue();
                //计算出其中的最大值
                Integer maxCount = countList.stream().max(Integer::compareTo).get();

                if (StringUtils.equals(saveEntry.getKey(), "正确")) {
                    isRightVO.setMaxCorrect(maxCount);
                }
                if (StringUtils.equals(saveEntry.getKey(), "错误")) {
                    isRightVO.setMaxError(maxCount);
                }
            }

            countMap.put(entry.getKey(), isRightVO);

            //进入计算下一个用户之前 先要清空上一个用户的状态
            status = null;
            saveMap = Maps.newHashMap();
        }

        return countMap;
    }

    /**
     * 递归计算
     * @param queue
     * @param resultMap
     */
    private void calculation(Queue<Record> queue, Map<String, Integer> resultMap) {

        //将首个元素从队列中弹出，如果队列是空的，就返回null
        Record record = queue.poll();

        //跳出递归条件
        if (Objects.isNull(record)) {
            return;
        }

        //最大连胜和最大连败 计算逻辑
        getResultMap(record, resultMap);

        //上一次的状态
        status = record.getIsRight();

        //递归继续向下执行
        calculation(queue, resultMap);
    }

    /**
     * 最大连胜和最大连败 计算逻辑
     * @param record
     * @param resultMap
     * @return
     */
    private Map<String, Integer> getResultMap(Record record, Map<String, Integer> resultMap) {
        //答题结果
        String isRight = record.getIsRight();

        //比较这一次状态和上一次状态 状态相等继续加1
        if (StringUtils.equals(isRight, status)) {
            Integer count = resultMap.get(isRight);
            resultMap.put(isRight, count + 1);
            //保留这次的计算结果
            saveCalculationResult(isRight, count + 1);
            return resultMap;
        }

        //状态不相等
        Integer count = resultMap.get(isRight);
        if (Objects.isNull(count)) {
            count = 1;
        }

        //保留这次的计算结果
        saveCalculationResult(isRight, count);

        //重新开始计算次数
        resultMap.put(isRight, 1);
        return resultMap;
    }

    /**
     * 保留这次的计算结果
     * @param isRight
     * @param count
     */
    private void saveCalculationResult(String isRight, Integer count) {
        List<Integer> countList = Lists.newArrayList();
        if (! saveMap.isEmpty()) {
            if (saveMap.containsKey(isRight)) {
                countList = saveMap.get(isRight);
            }
        }
        countList.add(count);
        saveMap.put(isRight, countList);
    }

    /**
     * 数据递归转化
     * @param queue
     * @param recordMap
     */
    private void dataMapping(Queue<Record> queue, Map<String, List<Record>> recordMap) {

        //将首个元素从队列中弹出，如果队列是空的，就返回null
        Record record = queue.poll();

        //跳出递归条件
        if (Objects.isNull(record)) {
            return;
        }

        //openid作为key ，record对象集合作为value 组装数据
        recordMap = getRecordMap(record, recordMap);

        //递归继续向下执行
        dataMapping(queue, recordMap);
    }


    /**
     * openid作为key ，record对象集合作为value 组装数据
     * @param record
     * @param recordMap
     * @return
     */
    private Map<String, List<Record>> getRecordMap(Record record, Map<String, List<Record>> recordMap) {
        //用户唯一标识
        String openid = record.getOpenid();

        if (! recordMap.isEmpty()) {
            if (recordMap.containsKey(openid)) {
                List<Record> recordList = recordMap.get(openid);
                recordList.add(record);
                return recordMap;
            }
        }

        List<Record> recordList = Lists.newArrayList();
        recordList.add(record);
        recordMap.put(openid, recordList);
        return recordMap;
    }



}
